<?php

/**
 * 数据库操作简化类
 * @author Echo Wang <wgqi1126@qq.com>
 */
class DB {

  /**
   * 配置
   * @var array
   */
  protected static $conf = array();

  /**
   * 数据库连接实例
   * @var PDO
   */
  protected static $pdo;

  /**
   * Prepare结果
   * @var array(PDOStatement)
   */
  protected static $pre;

  /**
   * 错误消息
   * @var array
   */
  protected static $error = null;

  /**
   * 初始化
   */
  public static function init ($dsn = 'mysql:host=localhost;port=3306;dbname=test', $username = 'root', $password = '', $charset = 'UTF8') {
    self::$conf = array('dsn' => $dsn, 'username' => $username, 'password' => $password, 'charset' => $charset);
  }

  /**
   * 返回PDO实例
   * @return PDO
   */
  public static function instance () {
    if (!self::$pdo) {
      self::$pdo = new PDO(self::$conf['dsn'] . ';charset=' . self::$conf['charset'], self::$conf['username'], self::$conf['password'], array(
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES '" . self::$conf['charset'] . "'"
      ));
      // 设置数据库查询返回的列的默认key为字段名F
      self::$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    }
    return self::$pdo;
  }

  /**
   * 获取错误信息
   * @return array
   */
  public static function getError () {
    return self::$error;
  }

  /**
   * 开始事务
   * @return bool
   */
  public static function beginTrans () {
    return self::instance()->beginTransaction();
  }

  /**
   * 提交事务
   * @return bool
   */
  public static function commit () {
    return self::instance()->commit();
  }

  /**
   * 回滚事务
   * @return bool
   */
  public static function rollBack () {
    return self::instance()->rollBack();
  }

  /**
   * 执行查询
   * @return PDOStatement
   */
  public static function query ($sql, $data = array()) {
    if (!self::$pre[$sql]) { // 未Prepare过
      $pdo = self::instance();
      self::$pre[$sql] = $pdo->prepare($sql);
      if (self::$pre[$sql] === false) { // Prepare失败
        self::$error = $pdo->errorInfo();
        self::$error['sql'] = $sql;
        self::$error['data'] = $data;
        return false;
      }
    }
    if (self::$pre[$sql]->execute($data) === false) { // 执行失败
      self::$error = self::$pre[$sql]->errorInfo();
      self::$error['sql'] = $sql;
      self::$error['data'] = $data;
      return false;
    }
    return self::$pre[$sql];
  }

  /**
   * 执行SQL，并返回受影响的条数
   * @param string $sql 要执行的SQL
   * @param array $data SQL中的数据
   * @return int|boolean 成功时返回受影响的行数，失败返回false
   */
  public static function execute ($sql, $data = array()) {
    $query = self::query($sql, $data);
    if ($query === false) return false;
    return $query->rowCount();
  }

  /**
   * 执行查询并获取第一行数据的指定列
   * @return array
   */
  public static function fetchColumn ($sql, $data = array(), $num = 0) {
    $query = self::query($sql, $data);
    if ($query === false) return false;
    $rs = $query->fetchColumn($num);
    if ($rs === false) return null;
    return $rs;
  }

  /**
   * 执行查询并获取第一行数据
   * @return array
   */
  public static function fetch ($sql, $data = array()) {
    $query = self::query($sql, $data);
    if ($query === false) return false;
    $rs = $query->fetch();
    if ($rs === false) return null;
    return $rs;
  }

  /**
   * 执行查询并获取所有数据
   * @return array
   */
  public static function fetchAll ($sql, $data = array()) {
    $query = self::query($sql, $data);
    if ($query === false) return false;
    return $query->fetchAll();
  }

  /**
   * 插入数据
   * @param string $table
   * @param array $data
   * @return int|boolean 成功返回最后一条插入的ID，失败返回false
   */
  public static function insert ($table, $data) {
    $keys = $pars = $vals = array();
    foreach ($data as $k => $v) {
      $keys[] = "`{$k}`";
      $pars[] = "?";
      $vals[] = $v;
    }
    $sql = "INSERT INTO `{$table}` (" . implode(', ', $keys) . ") VALUES (" . implode(', ', $pars) . ")";
    $rowCount = self::execute($sql, $vals);
    if ($rowCount === false) return false;
    return self::lastInsertId();
  }

  /**
   * 更新数据
   * @param string $table
   * @param array $setArr
   * @param string $whereSql
   * @param array $whereData
   * @return int|boolean 成功返回受影响的记录数，失败返回false
   */
  public static function update ($table, $setArr, $whereSql = '', $whereData = array()) {
    $kps = $vals = array();
    foreach ($setArr as $k => $v) {
      if (preg_match('%^\s*@\s*([\+\-\*/])\s*(.*)$%', $v, $m)) {
        $kps[] = "`{$k}` = `{$k}` {$m[1]} ?";
        $vals[] = $m[2];
      } else {
        $kps[] = "`{$k}` = ?";
        $vals[] = $v;
      }
    }
    $sql = "UPDATE `{$table}` SET " . implode(', ', $kps);
    if ($whereSql) $sql .= " WHERE {$whereSql}";
    $vals = array_merge($vals, $whereData);
    return self::execute($sql, $vals);
  }

  /**
   * 删除记录
   * @param string $table
   * @param string $whereSql
   * @param array $whereData
   * @return int|boolean 成功返回删除的行数，失败返回false
   */
  public static function delete ($table, $whereSql = '', $whereData = array()) {
    $sql = "DELETE FROM `{$table}`";
    if ($whereSql) $sql .= " WHERE {$whereSql}";
    return self::execute($sql, $whereData);
  }

  /**
   * 获取最后插入的ID
   * @return int
   */
  public static function lastInsertId () {
    $pdo = self::instance();
    return intval($pdo->lastInsertId());
  }

}
